<template>
  <el-card shadow="hover" class="mt-20">
    <el-form
      label-width="100px"
      :model="spuFormData"
      :rules="spuFormRules"
      ref="spuFormRef"
    >
      <el-form-item label="SPU名称" prop="spuName">
        <el-input placeholder="请输入SPU名称" v-model="spuFormData.spuName" />
      </el-form-item>

      <el-form-item label="品牌" prop="tmId">
        <el-select placeholder="请选择品牌" v-model="spuFormData.tmId">
          <el-option
            v-for="tm in trademarkList"
            :key="tm.id"
            :label="tm.tmName"
            :value="tm.id"
          ></el-option>
        </el-select>
      </el-form-item>

      <el-form-item label="SPU描述" prop="description">
        <el-input
          type="textarea"
          placeholder="请输入SPU描述"
          :rows="3"
          v-model="spuFormData.description"
        />
      </el-form-item>

      <el-form-item label="SPU图片" prop="spuImageList">
        <!-- 
          v-model:file-list="fileList" 图片列表
          action 上传服务器地址
          list-type="picture-card" 上传图片组件效果
          :on-preview 点击预览图表触发的函数
          :before-upload 上传之前触发的函数
          :limit 限制上传文件的数量
          accept 允许上传文件类型 
            image/* 所有图片类型
            image/png,image/jpg,image/jpeg
          multiple 是否支持多选文件
         -->
        <el-upload
          v-model:file-list="spuFormData.spuImageList"
          :action="`${BASE_URL}/admin/product/fileUpload`"
          list-type="picture-card"
          :on-preview="handlePictureCardPreview"
          :before-upload="beforeAvatarUpload"
          :limit="LIMIT"
          :on-exceed="handleExceed"
          accept="image/png,image/jpg,image/jpeg"
          multiple
          :on-success="handleSuccess"
        >
          <el-icon><Plus /></el-icon>

          <template #tip>
            <p>只能上传jpg/png文件，且不超过300kb</p>
          </template>
        </el-upload>

        <el-dialog v-model="dialogVisible" width="30%">
          <img :src="dialogImageUrl" alt="预览图片" class="preview-img" />
        </el-dialog>
      </el-form-item>

      <el-form-item label="销售属性" prop="spuSaleAttrList">
        <el-select
          :placeholder="
            unselectedBaseSaleAttrList.length === 0
              ? '没有啦'
              : `还剩${unselectedBaseSaleAttrList.length}个未选择`
          "
          class="mr-10"
          v-model="selectedBaseSaleAttr"
        >
          <el-option
            v-for="baseSaleAttr in unselectedBaseSaleAttrList"
            :key="baseSaleAttr.id"
            :label="baseSaleAttr.name"
            :value="`${baseSaleAttr.id}:${baseSaleAttr.name}`"
          ></el-option>
        </el-select>

        <el-button
          type="primary"
          :icon="Plus"
          :disabled="!selectedBaseSaleAttr"
          @click="addSaleAttr"
        >
          添加销售属性
        </el-button>

        <el-table :data="spuFormData.spuSaleAttrList" border class="mt-20">
          <el-table-column
            type="index"
            label="序号"
            align="center"
            width="60"
          ></el-table-column>
          <el-table-column
            label="销售属性名"
            prop="saleAttrName"
            width="150"
          ></el-table-column>
          <el-table-column label="销售属性值列表">
            <template v-slot="{ row }">
              <el-tag
                v-for="(saleAttrValue, index) in row.spuSaleAttrValueList"
                :key="saleAttrValue.saleAttrValueName"
                type="success"
                closable
                class="mr-10"
                @close="delSaleAttrValue(row, index)"
              >
                {{ saleAttrValue.saleAttrValueName }}
              </el-tag>
              <el-input
                placeholder="请输入销售属性值"
                size="small"
                class="spu-input"
                ref="inputRef"
                v-if="row.isShowEdit"
                v-model="saleAttrValueName"
                @blur="switchShow(row)"
              />
              <el-button
                :icon="Plus"
                size="small"
                v-else
                @click="switchEdit(row)"
              ></el-button>
            </template>
          </el-table-column>
          <el-table-column label="操作" width="80">
            <template v-slot="{ $index }">
              <el-button
                :icon="Delete"
                type="danger"
                size="small"
                @click="delSaleAttr($index)"
              ></el-button>
            </template>
          </el-table-column>
        </el-table>
      </el-form-item>

      <el-form-item>
        <el-button type="primary" @click="addOrUpdateSpu">保存</el-button>
        <el-button @click="cancel">取消</el-button>
      </el-form-item>
    </el-form>
  </el-card>
</template>

<script lang="ts" setup>
import { onMounted, ref, reactive, computed, nextTick } from "vue";
import { Plus, Delete } from "@element-plus/icons-vue";
import { getAllTrademarkListApi } from "@/api/product/trademark";
import {
  getBaseSaleAttrListApi,
  addSpuApi,
  getSpuImageListApi,
  getSpuSaleAttrListApi,
  updateSpuApi,
} from "@/api/product/spu";
import type { TrademarkList } from "@/api/product/models/trademarkModels";
import type {
  BaseSaleAttrList,
  SpuFormData,
  SpuSaleAttrItem,
  SpuSaleAttrList,
} from "@/api/product/models/spuModels";
import type { UploadProps } from "element-plus";
import { useCategoryStore } from "@/stores/category";
import { useSpuStore } from "@/stores/spu";

defineOptions({
  name: "AddOrUpdateSpu",
});

// 7. 销售属性值功能
const inputRef = ref();

const switchEdit = async (row: SpuSaleAttrItem) => {
  row.isShowEdit = true;
  await nextTick();
  inputRef.value.focus();
};

const saleAttrValueName = ref("");

const switchShow = (row: SpuSaleAttrItem) => {
  if (saleAttrValueName.value) {
    if (
      row.spuSaleAttrValueList.some(
        (saleAttrValue) =>
          saleAttrValue.saleAttrValueName === saleAttrValueName.value
      )
    ) {
      ElMessage.warning("不能添加重复的销售属性值");
      inputRef.value.focus();
      return;
    }
    row.spuSaleAttrValueList.push({
      baseSaleAttrId: row.baseSaleAttrId,
      saleAttrValueName: saleAttrValueName.value,
    });
    saleAttrValueName.value = "";
  }
  row.isShowEdit = false;
};

const delSaleAttrValue = (row: SpuSaleAttrItem, index: number) => {
  row.spuSaleAttrValueList.splice(index, 1);
};

// 6. 销售属性功能
const selectedBaseSaleAttr = ref("");

const unselectedBaseSaleAttrList = computed(() => {
  // 拿到 baseSaleAttrList 对 spuSaleAttrList 进行过滤，只保留没有再 spuSaleAttrList 中的属性
  return baseSaleAttrList.value.filter((baseSaleAttr) => {
    return !spuFormData.spuSaleAttrList.some(
      (saleAttr) => saleAttr.baseSaleAttrId === baseSaleAttr.id
    );
  });
});

const addSaleAttr = () => {
  const [id, name] = selectedBaseSaleAttr.value.split(":");
  spuFormData.spuSaleAttrList.push({
    baseSaleAttrId: +id, // 基础销售属性id
    saleAttrName: name, // 销售属性名称 - 来自基础销售属性名称
    spuSaleAttrValueList: [],
    isShowEdit: false,
  });
  selectedBaseSaleAttr.value = "";
};

const delSaleAttr = (index: number) => {
  spuFormData.spuSaleAttrList.splice(index, 1);
};

// 5. 添加或更新spu
const categoryStore = useCategoryStore();

const addOrUpdateSpu = async () => {
  await spuFormRef.value.validate();

  const id = spuStore.id;

  const spuData = {
    ...spuFormData,
    spuImageList: spuFormData.spuImageList.map((img) => {
      return {
        imgName: img.name,
        // unknown 类型想要读取内部的内容，需要类型断言
        imgUrl: (img.response as { data: string }).data,
      };
    }),
    category3Id: categoryStore.category3Id,
  };

  if (id) {
    await updateSpuApi({
      id,
      ...spuData,
    });
  } else {
    await addSpuApi(spuData);
  }

  ElMessage.success(`${id ? "更新" : "添加"}SPU成功`);

  cancel();
};

// 4. 收集&校验表单数据
const spuFormRef = ref();

const spuStore = useSpuStore();

const spuFormData = reactive<SpuFormData>({
  spuName: spuStore.spuName,
  tmId: spuStore.tmId,
  description: spuStore.description,
  spuImageList: [
    // {
    //   "id": 0,
    //   "imgName": "string",
    //   "imgUrl": "string",
    //   "spuId": 0
    // }
  ],
  spuSaleAttrList: [
    // {
    //   baseSaleAttrId: 0, // 基础销售属性id
    //   saleAttrName: "string", // 销售属性名称 - 来自基础销售属性名称
    //   spuSaleAttrValueList: [ // 销售属性值列表
    //     {
    //       baseSaleAttrId: 0,
    //       saleAttrValueName: "string",
    //     },
    //   ],
    // },
  ],
});

const spuSaleAttrListValidator = (
  _rule: any,
  value: SpuSaleAttrList,
  callback: any
) => {
  /*
    rule 就是当前表单项校验规则
    value 就是当前表单项的值
    callback 是一个函数，必须要调用
      callback() 调用不传参，校验通过
      callback(new Error('xxx')) 调用传参，校验失败，传递的参数就是失败的原因
  */
  // 至少有一个销售属性
  if (!value.length) {
    callback(new Error("请至少添加一个销售属性"));
    return;
  }
  // 每个销售属性至少有一个销售属性值
  if (!value.every((saleAttr) => saleAttr.spuSaleAttrValueList.length)) {
    callback(new Error("每个销售属性至少添加一个销售属性值"));
    return;
  }

  callback(); // 必须调用
};

const spuFormRules = reactive({
  spuName: [{ required: true, message: "请输入SPU名称", trigger: "blur" }],
  tmId: [{ required: true, message: "请选择SPU品牌", trigger: "change" }],
  description: [{ required: true, message: "请输入SPU描述", trigger: "blur" }],
  spuImageList: [
    { required: true, message: "请上传SPU图片", trigger: "change" },
  ],
  spuSaleAttrList: [
    { required: true, validator: spuSaleAttrListValidator, trigger: "blur" },
  ],
});

// 3. 上传图片功能
// const fileList = ref<UploadUserFile[]>([]);
const BASE_URL = import.meta.env.VITE_API_URL;

const dialogImageUrl = ref("");
const dialogVisible = ref(false);

// 预览图片
const handlePictureCardPreview: UploadProps["onPreview"] = (uploadFile) => {
  dialogImageUrl.value = uploadFile.url as string;
  dialogVisible.value = true;
};

const beforeAvatarUpload: UploadProps["beforeUpload"] = (rawFile) => {
  // rawFile 上传的文件对象
  // rawFile.type 文件类型 image/jpeg image/jpg image/png
  // rawFile.size 文件大小 单位：byte
  const validFileTypes = ["image/jpeg", "image/jpg", "image/png"];

  if (!validFileTypes.includes(rawFile.type)) {
    ElMessage.error("上传的图片只能是jpeg或png格式!");
    return false; // 返回false，就不会上传文件
  } else if (rawFile.size > 300 * 1024) {
    ElMessage.error("上传的图片文件大小不能超过300KB!");
    return false;
  }

  return true; // 返回true，就继续上传文件
};

// 限制上传文件数量
const LIMIT = 10;

const handleExceed = () => {
  ElMessage.error(`上传的图片不能超过${LIMIT}张！`);
};

const handleSuccess = () => {
  spuFormRef.value.clearValidate(["spuImageList"]);
};

// 2. 获取品牌和基础销售属性列表展示
const trademarkList = ref<TrademarkList>([]);
const baseSaleAttrList = ref<BaseSaleAttrList>([]);

// onMounted(async () => {
//   // 等第一个请求完后，才会发送第二个请求（请求比较慢）
//   // trademarkList.value = await getAllTrademarkListApi();
//   // baseSaleAttrList.value = await getBaseSaleAttrListApi();
//   const res = await Promise.all([
//     getAllTrademarkListApi(),
//     getBaseSaleAttrListApi(),
//   ]);
//   trademarkList.value = res[0];
//   baseSaleAttrList.value = res[1];
// });

// 所有生命周期函数可以写n个
onMounted(async () => {
  trademarkList.value = await getAllTrademarkListApi();
});

onMounted(async () => {
  baseSaleAttrList.value = await getBaseSaleAttrListApi();
});

onMounted(async () => {
  if (!spuStore.id) return;
  /*
    getSpuImageListApi 发送请求得到的图片数据：imgName imgUrl
    spuFormData.spuImageList 组件需要的图片数据：name url
  */
  const spuImageList = await getSpuImageListApi(spuStore.id as number);
  spuFormData.spuImageList = spuImageList.map((img) => {
    return {
      name: img.imgName,
      url: img.imgUrl,
      response: {
        // 将来添加或更新spu时候，图片数据url找到是img.response.data, 所以这个属性要有值
        data: img.imgUrl,
      },
    };
  });
});

onMounted(async () => {
  if (!spuStore.id) return;
  spuFormData.spuSaleAttrList = await getSpuSaleAttrListApi(
    spuStore.id as number
  );
});

// 1. 取消
const emit = defineEmits(["setIsShow"]);

const cancel = () => {
  emit("setIsShow", 1);
};
</script>

<style scoped lang="scss">
:deep(.el-form-item__label) {
  font-weight: 700;
}

.preview-img {
  width: 100%;
}

.spu-input {
  width: 150px;
}
</style>
